#include "server.h"
#include <QDebug>

server* server::s_inst = 0;
server::server(QObject *parent) : QObject(parent)
  ,ss(-1)
  ,sc(-1)
{

}

server *server::inst()
{
    if(s_inst == 0)
    {
        s_inst = new server();
    }
    return s_inst;
}

void server::registServer()
{
    sockaddr_in server_addr; //存储服务器端socket地址结构
    sockaddr_in client_addr; //存储客户端 socket地址结构

    int err;    //返回值
    pid_t pid;  //分叉进行的ID

    /*****************socket()***************/
    ss = socket(AF_INET,SOCK_STREAM,0); //建立一个序列化的，可靠的，双向连接的的字节流
    if(ss<0)
    {
        printf("server : server socket create error\n");
        return;
    }

    /******************bind()****************/
    //初始化地址结构
    memset(&server_addr,0,sizeof(server_addr));
    server_addr.sin_family = AF_INET;           //协议族
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);   //本地地址
//    server_addr.sin_addr.s_addr = inet_addr(SERVERIP);
    server_addr.sin_port = htons(PORT);

    err = bind(ss,(sockaddr *)&server_addr,sizeof(sockaddr));
    if(err < 0)
    {
        printf("server : bind error\n");
        return;
    }

    /*****************listen()***************/
    err = listen(ss,BACKLOG);   //设置监听的队列大小
    if(err < 0)
    {
        printf("server : listen error\n");
        return;
    }

    /****************accept()***************/
    /**
    为方便处理，我们使用两个进程分别管理两个处理：
    1，服务器监听新的连接请求;2,以建立连接的C/S实现通信
    这两个任务分别放在两个进程中处理，为了防止失误操作
    在一个进程中关闭 侦听套接字描述符 另一进程中关闭
    客户端连接套接字描述符。注只有当所有套接字全都关闭时
    当前连接才能关闭，fork调用的时候父进程与子进程有相同的
    套接字，总共两套，两套都关闭掉才能关闭这个套接字
    */
    qDebug()<<"service regist ok!";
    while(1)
    {
        socklen_t addrlen = sizeof(client_addr);
        //accept返回客户端套接字描述符
        sc = accept(ss,(sockaddr *)&client_addr,&addrlen);  //注，此处为了获取返回值使用 指针做参数
        if(sc < 0)  //出错
        {
            continue;   //结束此次循环
        }
        else
        {
            qDebug()<<sc<<" client connected!";
        }

        //创建一个子进程，用于与客户端通信
        pid = fork();
        //fork 调用说明：子进程返回 0 ；父进程返回子进程 ID
        if(pid == 0)        //子进程，与客户端通信
        {
            close(ss);
            handle();
        }
        else
        {
            close(sc);
        }

    }
}

int server::closeServer()
{
    int ret1 = close(ss);
    int ret2 = close(sc);
    int ret = ret1>ret2?ret1:ret2;
    return ret;
}

//通过套接字 s 与客户端进行通信
void server::handle()
{
    ssize_t size = 0;
    data d;  //定义数据缓冲区
    while(1)
    {
        //等待读
        for(size = 0; size == 0; size = read(sc,&d,1024));
        {
            //输出从客户端接收到的数据
            switch (d.cmd) {
            case CMD_REJEST:

                break;
            case CMD_LOGIN:
                break;
            case CMD_SENDMESSAGE:
                cout<<d.buf<<endl;
                sendMesssage(d);
                break;
            default:
                break;
            }
        }
        //结束处理
        if(strcmp(d.buf,"quit") == 0)
        {
            close(sc);   //成功返回0，失败返回-1
            return ;
        }
    }
}

void server::sendMesssage(data d)
{
    cout<<"sendMsg"<<d.receiver<<endl;
    write(sc,&d,sizeof(d));
}
